In [ ]:
import matplotlib.pyplot as plt
%matplotlib inline

텐서플로우 라이브러리를 임포트 하세요.


In [ ]:

텐서플로우에는 MNIST 데이터를 자동으로 로딩해 주는 헬퍼 함수가 있습니다. "MNIST_data" 폴더에 데이터를 다운로드하고 훈련, 검증, 테스트 데이터를 자동으로 읽어 들입니다. one_hot 옵션을 설정하면 정답 레이블을 원핫벡터로 바꾸어 줍니다.


In [ ]:
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)

minist.train.images에는 훈련용 이미지 데이터가 있고 mnist.test.images에는 테스트용 이미지 데이터가 있습니다. 이 데이터의 크기를 확인해 보세요.


In [ ]:

matplotlib에는 이미지를 그려주는 imshow() 함수가 있습니다. 우리가 읽어 들인 mnist.train.images는 길이 784의 배열입니다. 55,000개 중에서 원하는 하나를 출력해 보세요.

이미지로 표현하려면 원본 이미지 사각형 크기인 [28, 28]로 변경해 줍니다. 그리고 흑백이미지 이므로 컬러맵을 그레이 스케일로 지정합니다.


In [ ]:
plt.imshow(mnist.train.images[..].reshape([.., ..]), cmap=plt.get_cmap('gray_r'))

mnist.train.labels에는 정답값 y 가 들어 있습니다. 원핫벡터로 로드되었는지 55,000개의 정답 데이터 중 하나를 확인해 보세요.


In [ ]:
mnist.train.labels[..]

훈련 데이터는 55,000개로 한꺼번에 처리하기에 너무 많습니다. 그래서 미니배치 그래디언트 디센트 방식을 사용하려고 합니다. 미니배치 방식을 사용하려면 훈련 데이터에서 일부를 쪼개어 반복하여 텐서플로우 모델에 주입해 주어야 합니다.

텐서플로우 모델이 동작하면서 입력 데이터를 받기위해 플레이스 홀더를 정의합니다. 플레이스 홀더는 x(이미지), y(정답 레이블) 두가지입니다.

x = tf.placeholder("float32", [None, 784]) y = tf.placeholder("float32", shape=[None, 10])


In [ ]:

첫번째 레이어의 행렬식을 만듭니다. 이 식은 입력 데이터 x와 첫번째 레이어의 가중치 W1을 곱하고 편향 b1을 더합니다.

첫번째 레이어의 뉴런(유닛) 개수를 100개로 지정하겠습니다. 입력 데이터 x 는 [None, 784] 사이즈의 플레이스 홀더이므로 가중치의 크기는 [784, 100] 이 되어야 결과 행렬이 [None, 100] 이 되어 다음 레이어로 전달됩니다.

W1 = tf.Variable(tf.truncated_normal([784, 100], stddev=0.1)) b1 = tf.Variable(tf.constant(0.1, shape=[100]))


In [ ]:

tf.matmul 함수를 사용하여 행렬곱을 한다음 편향을 더하고 첫번째 레이어의 활성화 함수인 시그모이드 함수를 적용합니다. 텐서플로우에는 시그모이드 함수를 내장하고 있습니다.

t = tf.sigmoid(tf.matmul(x,W1) + b1)


In [ ]:

출력 레이어의 계산식을 만들기 위해 가중치 W2와 b2 변수를 만듭니다. 직전의 히든 레이어의 출력 사이즈가 [None, 100]이고 출력 유닛의 개수는 10개 이므로 가중치 W2의 크기는 [100, 10] 이 됩니다. 편향 b2의 크기는 [10]입니다.

W2 = tf.Variable(tf.truncated_normal([100, 10], stddev=0.1)) b2 = tf.Variable(tf.constant(0.1, shape=[10]))


In [ ]:

출력 레이어의 행렬곱을 계산합니다. 이전 히든 레이어의 출력 t와 W2를 곱하고 b2를 더합니다.

z = tf.matmul(t,W2) + b2


In [ ]:

출력 값을 정규화하여 정답과 비교하려면 소프트맥스 함수를 적용해야 합니다. 텐서플로우에는 소프트맥스 함수가 내장되어 있습니다.

y_hat = tf.nn.softmax(z)


In [ ]:

손실 함수 크로스 엔트로피를 계산하기 위해 위에서 구한 y_hat을 사용해도 되지만 텐서플로우에는 소프트맥스를 통과하기 전의 값 z 를 이용하여 소프트맥스 크로스 엔트로피를 계산해 주는 함수를 내장하고 있습니다. softmax_cross_entropy를 이용하여 z 와 정답 y 의 손실을 계산합니다.

loss = tf.losses.softmax_cross_entropy(y, z)

학습속도 0.5로 경사하강법을 적용하고 위에서 만든 손실 함수를 이용해 훈련 노드를 생성합니다.

optimizer = tf.train.GradientDescentOptimizer(0.5) train = optimizer.minimize(loss)


In [ ]:

올바르게 분류된 정확도를 계산하려면 정답을 가지고 있는 원핫벡터인 y 와 소프트맥스를 통과한 원핫벡터인 y_hat을 비교해야 합니다. 이 두 텐서는 [None, 10]의 크기를 가지고 있습니다. 따라서 행방향(1)으로 가장 큰 값을 가진 인덱스(argmax)를 찾아서 같은지(equal) 확인하면 됩니다.

correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_hat,1))

correct_prediction은 [True, False, ...] 와 같은 배열이므로 불리언을 숫자(1,0)로 바꾼다음(cast) 전체를 합하여 평균을 내면 정확도 값을 얻을 수 있습니다.

accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))


In [ ]:

세션 객체를 만들고 모델에 사용할 변수를 초기화합니다.


In [ ]:
sess = tf.Session()
sess.run(tf.global_variables_initializer())

1000번 반복을 하면서 훈련 데이터에서 100개씩 뽑아내어(mnist.train.next_batch) 모델에 주입합니다. 모델의 플레이스 홀더에 주입하려면 플레이스 홀더의 이름과 넘겨줄 값을 딕셔너리 형태로 묶어서 feed_dict 매개변수에 전달합니다.

계산할 값은 훈련 노드 train 과 학습 과정을 그래프로 출력하기 위해 손실함수 값을 계산하여 costs 리스트에 누적합니다.


In [ ]:
costs = []
for i in range(1000):
    x_data, y_data = mnist.train.next_batch(100)
    _, cost = sess.run([train, loss], feed_dict={x: x_data, y: y_data})
    costs.append(cost)

costs 리스트를 그래프로 출력합니다.


In [ ]:
plt.plot(costs)

정확도를 계산하기 위해 만든 노드 accuracy를 실행합니다. 이때 입력 데이터는 mnist.test 로 훈련시에 사용하지 않았던 데이터입니다. 이 정확도 계산은 위에서 학습시킨 W1, b1, W2, b2 를 이용하여 레이블을 예측한 결과입니다.

sess.run(accuracy, feed_dict={x: mnist.test.images, y: mnist.test.labels})


In [ ]:

실제 이미지와 예측 값이 동일한지 확인하기 위해 테스트 데이터 앞의 5개 이미지와 예측 값을 차례대로 출력해 봅니다.


In [ ]:
for i in range(5):
    plt.imshow(mnist.test.images[i].reshape([28, 28]), cmap=plt.get_cmap('gray_r'))
    plt.show()
    print(sess.run(tf.argmax(y_hat,1), feed_dict={x: mnist.test.images[i].reshape([1,784])}))